/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright 
     notice, this list of conditions and the following disclaimer in 
     the documentation and/or other materials provided with the distribution.

  3. The names of the authors may not be used to endorse or promote products
     derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.jcraft.jsch;

/**
 * 2025.6.27: 获取执行通道
 * <p>
 * 2025.6.30: 按照SSH协议架构，标准将SSH分成三层：传输层协议、用户认证协议、连接协议
 * 2025.6.30: 1) 最底层的是传输层协议，它负责认证服务器，加密数据，确保数据完整性，虽然它运行在TCP之上，
 * 但其实它可以运行在任意可靠的数据流之上；
 * 2025.6.30: 2) 第二层是用户认证协议，它负责认证使用者是否是ssh服务器的用户，
 * Public Key Authentication登陆ssh就将在这一层实现；
 * 2025.6.30: 3) 最上层是连接协议，它将把多路加密的通道转换成逻辑上的Channel
 * <p>
 * 2025.6.30: 父类ChannelSession.run()处理了报文
 * <p>
 * 2025.7.10：应用3：远程命令调用
 * <p>
 * 2025.7.15：命令通道只是简单实现，这不是jsch工程的重点。ssh协议的重点是第一层的加密算法
 * <p>
 * 2025.7.20：这种方式慎用，很多交换机不支持（CentOS都是支持的），会报exit-status=19的错误。
 */
public class ChannelExec extends ChannelSession {

    byte[] command = new byte[0];

    /**
     * 2025.6.27: 启动一个线程来与ssh服务器对话
     *
     * @throws JSchException
     */
    public void start() throws JSchException {
        //2025.6.27: 获取会话
        Session _session = getSession();
        try {
//            JSch.logInfo("发送请求sendRequests");
            sendRequests();
            Request request = new RequestExec(command);
//            JSch.logInfo("请求RequestExec");
            request.request(_session, this);

//            JSch.logInfo("发送请求sendRequests结束");
        } catch (Exception e) {
            if (e instanceof JSchException) throw (JSchException) e;
            if (e instanceof Throwable)
                throw new JSchException("ChannelExec", (Throwable) e);
            throw new JSchException("ChannelExec");
        }
        /**
         * 2025.6.28: 通过线程来操作网络IO
         */
        if (io.in != null) {
            JSch.logInfo("发送请求io.in != null");

            thread = new Thread(this);
            thread.setName("Exec thread " + _session.getHost());
            if (_session.daemon_thread) {
                thread.setDaemon(_session.daemon_thread);
            }

            //2025.6.30: 参见ChannelSession.run()
            thread.start();
        }
    }

    /**
     * 2025.6.27: 设置命令
     *
     * @param command
     */
    public void setCommand(String command) {
        this.command = Util.str2byte(command);
    }

    public void setCommand(byte[] command) {
        this.command = command;
    }

    /**
     * 2025.6.28: 设置in和out的输出
     *
     * @throws JSchException
     */
    void init() throws JSchException {
        io.setInputStream(getSession().in);
        io.setOutputStream(getSession().out);
    }

    /**
     * 2025.7.11: 设置错误流的输出
     *
     * @param out
     */
    public void setErrStream(java.io.OutputStream out) {
        setExtOutputStream(out);
    }

    public void setErrStream(java.io.OutputStream out, boolean dontclose) {
        setExtOutputStream(out, dontclose);
    }

    public java.io.InputStream getErrStream() throws java.io.IOException {
        return getExtInputStream();
    }
}
